package estadistec.logica.tabla;

import java.util.Hashtable;

import estadistec.excepciones.ExcepcionLlaveInexistente;

import estadistec.logica.SuperGestor;
import estadistec.logica.LEscritorio;

import estadistec.logica.dependencias.IBuscarNodo;
import estadistec.logica.dependencias.Nodo;

import estadistec.logica.gestores.GestorManejable;
import estadistec.logica.gestores.Gestor;

/**
 * Gestiona cada una de las tablas. Representa un "escritorio".
 */
public class GestorTablas extends GestorManejable<LTabla> {

	private LEscritorio _lEscritorioPadre;

	public GestorTablas(LEscritorio escritorioPadre) {
		this._manejables = new Hashtable<Long, LTabla>();
		this._lEscritorioPadre = escritorioPadre;
		this._indNombre = 1;
	}

	protected String nombreManejable() {
		return ("Tabla");
	}

	/**
	 * Crea una nueva tabla en este gestor.
	 *
	 * @param tipo Tipo de tabla a crear.
	 *
	 * @return Referencia a la tabla creada.
	 */
	public LTabla crearLTabla(TipoTabla tipo) {
		Long llaveTemp = getNuevaLlave();
		LTabla nueva; 
		switch (tipo) {
			case NORMAL:
				nueva = new LTablaNormal (llaveTemp, nuevoNombreManejable(),
						this);
				break;
			case MUESTRA:
				nueva = new LTablaNormal (llaveTemp, "Muestra", this);
				break;
			case RESUMEN:
				nueva = new LTablaNormal (llaveTemp, "Resumen", this);
				break;
			default:
				nueva = new LTablaNormal (llaveTemp, "Default", this);
				// No es posible que llegue a este punto.
				assert (false);
		}
		this._manejables.put(llaveTemp, nueva);
		return nueva;
	}

	/** 
	 * Elimina una tabla.
	 * 
	 * @param llave Identificador de la tabla a eliminar.
	 *
	 * @throws ExcepcionLlaveInexistente La llave no sirve.
	 */
	public void eliminarLTabla(Long llave) 
		throws ExcepcionLlaveInexistente
	{
		// En caso de que la llave no referencia a ninguna tabla.
		if (!this._manejables.containsKey(llave))
			throw new ExcepcionLlaveInexistente("Llave : " + llave);

		// Nos aseguramos que la tabla está asilada.
		assert(!this._manejables.get(llave).tieneDependientes());
		// Este método le avisa a los superiores que ya no depende de ellos.
		this._manejables.get(llave).independizate();
		// Este método obliga a sus dependientes a independizarse.
		this._manejables.get(llave).liberarDependientes();
		this._manejables.remove(llave);

		// Enviando la al arreglo de llaves que se pueden utilizar.
		liberarLlave(llave);
	}

	/**
	 * Devuelve la Tabla identificada por @p idTabla
	 * 
	 * @param idTabla
	 *            Identificador de la tabla
	 * @return La tabla correspondiente
	 * @throws Excepcion
	 *             Si la tabla no existe
	 */
	public LTabla getLTabla(Long idTabla) 
		throws ExcepcionLlaveInexistente 
	{
		if (!this._manejables.containsKey(idTabla))
			throw new ExcepcionLlaveInexistente("Llave : " + idTabla);

		return this._manejables.get(idTabla);
	}

	/** 
	 * Método que busca un nodo según una cadena de nombres.
	 * Pasa directo al LEscritorio que lo maneja.
	 * 
	 * @param nombres Nombres de los padres y Nodo.
	 * @param nivel Nivel actual en los nombres.
	 * 
	 * @return Nodo que se busca o {@code null} si no está.
	 */
	public Nodo buscarRaiz(String[] nombres, int nivel) {
		return (_lEscritorioPadre.buscarNodo(nombres, nivel));
	}

	/** 
	 * Método que busca un nodo según una cadena de nombres. 
	 * 
	 * @param nombres Nombres de los padres y Nodo.
	 * @param nivel Nivel actual en los nombres.
	 * 
	 * @return Nodo que se busca o {@code null} si no está.
	 */
	public Nodo buscarNodo(String[] nombres, int nivel) {
		int n = nombres.length;
		// Solo faltan dos niveles para llegar a uno nodo.
		assert (nivel < n - 2);

		// Tabla donde es posible que se encuentre el Nodo.
		LTabla buscarEn = getManejableXNombre(nombres[nivel]);
		if (buscarEn == null)
			return null;
		return (buscarEn.buscarNodo(nombres, nivel + 1));
	}

	/** 
	 * Devuelve el SuperGestor.
	 * Aquí en lugar de devolver el escritorio se devuelve el Super Gestor,
	 * ello porque el Escritorio no es formalmente un gestor.
	 */
	public Gestor getGestor() {
		return SuperGestor.getInstancia();
	};

}
